/*
 * To change this template, choose Tools | Templates
 * and open the template in the editor.
 */
package multi.agent.simulation.behaviour;

import jade.core.AID;
import jade.core.behaviours.CyclicBehaviour;
import jade.lang.acl.ACLMessage;
import java.util.ArrayList;
import java.util.Iterator;
import javax.persistence.EntityManagerFactory;
import javax.persistence.Persistence;
import multi.agent.simulation.BestRoadReply;
import multi.agent.simulation.BestRoadRequest;
import multi.agent.simulation.LinkInfo;
import multi.agent.simulation.MessageResponce;
import multi.agent.simulation.TrafficAgent;
import multi.agent.simulation.dao.NodoJpaController;
import multi.agent.simulation.dao.RutasJpaController;
import multi.agent.simulation.entity.Rutas;
import multi.agent.simulation.listeners.InformListener;

/**
 *
 * @author Mauro Perez
 */
public class TrafficRequest extends CyclicBehaviour 
{
    private TrafficAgent _agent;
    private InformListener _informListener; 
    private final String _language = "English";
    private final String _ontology = "traffic-ontology";
    private ArrayList<Rutas> _rutas;
    private ArrayList<BestRoadRequest> _requests;
    
    
    public TrafficRequest(TrafficAgent agent) {
        _agent = agent;
        _rutas = new ArrayList<>();
        _requests = new ArrayList<>();
    }
    
    private void updateRutas(){
        EntityManagerFactory emf = Persistence.createEntityManagerFactory("multi-agent-simulationPU");
        RutasJpaController rutCon = new RutasJpaController(emf);
        NodoJpaController nodCon = new NodoJpaController(emf);
        _rutas = rutCon.findRutasEntities(nodCon.findNodo(_agent._dbID));
    }
    
    @Override
    public void action() 
    {
        //First, let's update the rutas from the db
        updateRutas();
        BestRoadReply rep;
        BestRoadRequest req;
        
        //Check incoming messages
        ACLMessage msg = _agent.receive();
        
        if(msg != null) 
        {
            switch(msg.getPerformative()) 
            {
                case ACLMessage.INFORM:
                    
                    System.out.println("Reply - " + _agent._agentName + ": " + msg.getContent());
                    
                    rep = BestRoadReply.FromMessageString(msg.getContent());
                    for (int i = 0; i < _requests.size(); i++){
                        req = _requests.get(i);
                        if (req.RequestID.equals( rep.RequestID)) {
                            Rutas ruta = GetRuta(_agent._agentName, rep.ReplierName);
                            //rep.Weight += (double)ruta.getDistancia() / (double)ruta.getVelocidadMaxima();
                            rep.Weight = 100.0;
                            rep.Road.add(_agent._agentName);
                            rep.ReplierName = _agent._agentName;
                            SendReply(req.RequesterName, rep);
                        }
                    }
                    
                    /*MessageResponceParser(msg);
                    if(_informListener != null)
                    {
                        _informListener.onInform();
                    }*/
                    break;
                    
                case ACLMessage.REQUEST:
                    //RequestManager(msg);
                    
                    if (_requests.size() > 0){
                        break;
                    }
                    
                    System.out.println("Request - " + _agent._agentName + ": " + msg.getContent());
                    
                    //we build the road request from the message
                    req = BestRoadRequest.FromMessageString(msg.getContent());
                    _requests.add(req);
                    
                    //if there are not rutas for this agent, send invalid reply
                    if (_rutas.size() == 0) {
                        rep = new BestRoadReply();
                        rep.RequestID = req.RequestID;
                        rep.ReplierName = _agent._agentName;
                        rep.IsValid = false;
                        SendReply(req.RequesterName, rep);
                    }
                    
                    //if this node is the destination then send valid reply
                    else if (_agent._agentName.equals(req.DestinationName)) {
                        rep = new BestRoadReply();
                        rep.RequestID = req.RequestID;
                        rep.ReplierName = _agent._agentName;
                        rep.IsValid = true;
                        rep.Road.add(_agent._agentName);
                        SendReply(req.RequesterName, rep);
                    }
                    
                    //ask other nodes
                    else {
                        //clone the req but setting this node as requester
                        BestRoadRequest fwdReq = BestRoadRequest.FromMessageString(req.toMessageString());
                            fwdReq.RequesterName = _agent._agentName;      
                        for (int i = 0; i < _rutas.size(); i++){
                            Rutas ruta = _rutas.get(i);
                            if (!ruta.getHasta().equals(req.RequesterName)){
                                SendRequest(ruta.getHasta().getNombre(), fwdReq);
                                req.RequestCount++;
                            }
                        }
                    }
                    
                    break;
                    
                default:
                    break;
            }
        }
        
        block();
    }
    
    private void SendReply(String to, BestRoadReply rep){
        ACLMessage msg = new ACLMessage(ACLMessage.INFORM); 
        msg.addReceiver(new AID(to, false));
        msg.setLanguage(_language);
        msg.setOntology(_ontology);
        msg.setContent(rep.toMessageString());
        _agent.send(msg);
    }
    
    private void SendRequest(String to, BestRoadRequest req){
        ACLMessage msg = new ACLMessage(ACLMessage.REQUEST); 
        msg.addReceiver(new AID(to, false));
        msg.setLanguage(_language);
        msg.setOntology(_ontology);
        msg.setContent(req.toMessageString());
        _agent.send(msg);
    }
    
    private Rutas GetRuta(String from, String to){
        for (int i = 0; i < _rutas.size(); i++){
            Rutas ruta = _rutas.get(i);
            if (ruta.getDesde().getNombre() == from && ruta.getHasta().getNombre() == to){
                return ruta;
            }
        }
        return null;
    }
    
    
    private void MessageResponceParser(ACLMessage msg)
    {
         //string representation of responce RequestID;OverHead;LinkSequence
        
        String[] temp = msg.getContent().split(";");
        
        try 
        {
            MessageResponce rps = new MessageResponce();
            rps.SenderId = msg.getSender().toString();
            rps.Id = temp[0];
            rps.OverHead = Integer.parseInt(temp[1]);
            rps.LinkSequence = temp[2];
            _agent.MsgRequest.responceList.add(rps);
            
        } catch (NumberFormatException e) 
        {
                // TODO Auto-generated catch block
        }
    }

    /**
     * @param informListener the _informListener to set
     */
    public void setInformListener(InformListener informListener) 
    {
        this._informListener = informListener;
    }

    private void RequestManager(ACLMessage msg) 
    {
        //string representation of request RequestID;OriginNode;DestinationNode
        // Send the request to each linked node.
        
        _agent.ResponceCounter = _agent.Links.size();
        Iterator it = _agent.Links.iterator();
        while(it.hasNext())
        {
            LinkInfo rt = (LinkInfo)it.next();
            SendMessageToLinkedNode(rt, msg.getContent());
        }
    }
    
    private void SendMessageToLinkedNode(LinkInfo target, String msgcontent)
    {
        ACLMessage msg = new ACLMessage(ACLMessage.REQUEST); 
        msg.addReceiver(new AID(target.NextLink, false));
        msg.setLanguage(_language);
        msg.setOntology(_ontology);
        msg.setContent(msgcontent);
        _agent.send(msg);
    }
    
}
